package com.think.cloud.thinkshop.mall.service.product.impl;


import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.think.cloud.thinkshop.common.constant.product.ProductConstants;
import com.think.cloud.thinkshop.mall.controller.app.order.vo.AppOrderCartRespVO;
import com.think.cloud.thinkshop.mall.controller.app.product.vo.*;
import com.think.cloud.thinkshop.mall.convert.product.ProductAttrConvert;
import com.think.cloud.thinkshop.mall.convert.product.ProductAttrValueConvert;
import com.think.cloud.thinkshop.mall.convert.product.ProductConvert;
import com.think.cloud.thinkshop.mall.domain.Product;
import com.think.cloud.thinkshop.mall.domain.ProductAttr;
import com.think.cloud.thinkshop.mall.domain.ProductAttrValue;
import com.think.cloud.thinkshop.mall.enums.common.CommonWhetherEnum;
import com.think.cloud.thinkshop.mall.enums.product.ProductShowEnum;
import com.think.cloud.thinkshop.mall.mapper.ProductAttrMapper;
import com.think.cloud.thinkshop.mall.mapper.ProductAttrValueMapper;
import com.think.cloud.thinkshop.mall.mapper.ProductMapper;
import com.think.cloud.thinkshop.mall.service.category.AppProductCategoryService;
import com.think.cloud.thinkshop.mall.service.product.AppProductService;
import com.think.cloud.thinkshop.mall.service.productgroup.IProductGroupRelationService;
import com.think.common.core.exception.enums.ErrorCode;
import com.think.common.core.exception.util.ServiceExceptionUtil;
import com.think.common.core.utils.PageUtils;
import com.think.common.core.web.page.TableDataInfo;
import com.think.common.redis.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 商品AppService业务层处理
 *
 * @author zkthink
 * @date 2024-05-14
 */
@Service
@Slf4j
public class AppProductServiceImpl implements AppProductService {

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private AppProductCategoryService appProductCategoryService;

    @Autowired
    private ProductAttrValueMapper productAttrValueMapper;

    @Autowired
    private ProductAttrMapper productAttrMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IProductGroupRelationService itemGroupRelationService;


    private Product findProductById(Long id) {
        return productMapper.selectById(id);
    }

    @Override
    public TableDataInfo selectProductList(AppProductPageReqVO vo) {
        // 查询包含该类目在内的所有子类目集合
        if (ObjectUtil.isNotNull(vo.getCategoryId()))
            vo.setCategoryIds(appProductCategoryService.getAllKidCategoryIds(vo.getCategoryId()));
        if (ObjectUtil.isNotNull(vo.getGroupId())) {
            vo.setProductIds(itemGroupRelationService.selectProductIdByGroupId(vo.getGroupId()));
        }
        List<Product> products = productMapper.selectList(vo);
        return new TableDataInfo(ProductConvert.INSTANCE.convertList1(products), PageUtils.getTotal(products));
    }

    @Override
    public AppProductDetailRespVO getProductDetail(Long productId) {
        AppProductDetailRespVO vo = ProductConvert.INSTANCE.convert3(this.findProductById(productId));
        if (ObjectUtil.isNotNull(vo.getCategoryId())) {
            vo.setCategoryPath(appProductCategoryService.getCategoryPath(vo.getCategoryId()));
        }
        // 获取规格
        List<AppProductAttrRespVO> productAttr =
                ProductAttrConvert.INSTANCE.convertList(
                        productAttrMapper.selectList(
                                new LambdaQueryWrapper<ProductAttr>()
                                        .eq(ProductAttr::getProductId, productId)
                                        .orderByAsc((ProductAttr::getAttrId))
                        )
                );
        if (CollectionUtils.isNotEmpty(productAttr)) {
            productAttr.forEach(res -> res.setAttrValueArr(Arrays.asList(res.getAttrValues().split(","))));
        }
        vo.setProductAttr(productAttr);
        // 获取规格属性
        List<AppProductSkuRespVO> skus = ProductAttrValueConvert.INSTANCE.convertList2(
                productAttrValueMapper.selectList(ProductAttrValue.builder().productId(productId).build())
        );
        if (CollectionUtils.isNotEmpty(skus)) {
            vo.setProductValue(skus.stream().collect(Collectors.toMap(AppProductSkuRespVO::getSku, Function.identity())));
        }
        // 增加浏览量
        productMapper.addPageViews(productId);
        return vo;
    }

    @Override
    public List<AppProductPageRespVO> recommendList(AppRecommendProductPageReqVO vo) {
        Product product = this.findProductById(vo.getProductId());
        LambdaQueryWrapper<Product> productQW = new LambdaQueryWrapper<>();
        productQW.ne(Product::getProductId, vo.getProductId());
        if (ObjectUtil.isNotNull(product.getCategoryId())) {
            productQW.eq(Product::getCategoryId, product.getCategoryId());
        }
        List<Product> products = productMapper.selectList(productQW);
        if (CollectionUtils.isEmpty(products)) {
            productQW = new LambdaQueryWrapper<>();
        }
        products = productMapper.selectList(productQW);
        return ProductConvert.INSTANCE.convertList1(products);
    }


    @Override
    public void checkProduct(Long productId) {
        Product product = this.findProductById(productId);
        // 校验商品是否存在
        if (ObjectUtil.isNull(product)) throw ServiceExceptionUtil.exception(ErrorCode.PRODUCT_NOT_EXIST_ERROR);
        // 检验是否下架
        if (ProductShowEnum.NO.getValue().equals(product.getIsShow()))
            throw ServiceExceptionUtil.exception(ErrorCode.PRODUCT_OFF_SHELF_ERROR);
    }

    @Override
    public void checkStock(Long skuId, Integer num) {
        ProductAttrValue sku = productAttrValueMapper.selectById(skuId);
        // 校验规格是否存在
        if (ObjectUtil.isNull(sku)) throw ServiceExceptionUtil.exception(ErrorCode.PRODUCT_SKU_NOT_EXIST_ERROR);
        // 校验库存
        if (sku.getStock() - num < 0)
            throw ServiceExceptionUtil.exception(ErrorCode.PRODUCT_INSUFFICIENT_INVENTORY_ERROR);
    }


    @Override
    public void handleStock(List<AppOrderCartRespVO> carts, Integer type) {
        for (AppOrderCartRespVO cart : carts) {
            String lockKey = ProductConstants.PRODUCT_LOCK_KEY + cart.getProductId();
            if (redisService.redisTemplate.opsForValue().setIfAbsent(lockKey, cart.getProductId())) {
                try {
                    // 校验库存
                    checkStock(cart.getSkuId(), cart.getNum());
                    // 根据类型扣减或回退库存和销量
                    handleStock(cart, type);
                } catch (Exception e) {
                    throw ServiceExceptionUtil.exception(ErrorCode.PRODUCT_STOCK_HANDLE_ERROR);
                } finally {
                    // 释放锁
                    redisService.deleteObject(lockKey);
                }
            }
        }
    }

    /**
     * 根据类型扣减或回退库存和销量
     *
     * @param vo
     * @param type 类型 0:回退；1:扣减
     */
    private void handleStock(AppOrderCartRespVO vo, Integer type) {
        if (CommonWhetherEnum.YES.getValue().equals(type)) {
            productAttrValueMapper.subStack(vo.getSkuId(), vo.getNum());
            productMapper.subStack(vo.getProductId(), vo.getNum());
        } else {
            productAttrValueMapper.addStack(vo.getSkuId(), vo.getNum());
            productMapper.addStack(vo.getProductId(), vo.getNum());
        }
    }

    @Override
    public List<Product> selectListWithDeleted(List<Long> productIds) {
        return productMapper.selectListWithDeleted(productIds);
    }
}
